//============================================================================
//	Johns Hopkins University Engineering for Professionals
//	605.467 Computer Graphics and 605.767 Applied Computer Graphics
//	Instructor:	David W. Nesbitt
//
//	Author:  David W. Nesbitt
//	File:    Segment.h
//	Purpose: 2D Line segment class. Includes clipping code. 
//          Student should  include "geometry.h" to get all class definitions
//          included in proper order.
//
//============================================================================

#ifndef __SEGMENT2_H__
#define __SEGMENT2_H__

#include <math.h>
#include <vector>

/**
 * Rectangle
 */
struct CRectangle
{
   float left;
   float right;
   float bottom;
   float top;
};


/**
 * Line segment in 2D
 */
struct LineSegment2
{
   Point2 A;
   Point2 B;

   /**
    * Default constructor.
    */
   LineSegment2(void)
   {
      A.Set(0.0f, 0.0f);
      B.Set(0.0f, 0.0f);
   }

   /**
    * Constructor given 2 points.
    * @param   p1    First point of the segment.
    * @param   p2    Second point of the segment.
    */
   LineSegment2(const Point2& p1, const Point2& p2)
   {
      A = p1;
      B = p2;
   }
      
   /**
    * Finds the distance of a specified point from the line segment 
    * and the closest point on the segement to the specified point.
    * @param   P           Test point.
    * @param   closestPt   (Return) Closest point on the segment to point P.
    * @return  Returns the distance from P to the closest point on
    *          the segment.
    */
   float Distance(const Point2& P, Point2& closestPt) const
   {
		// Student to define
		Vector2 v = B - A;
		Vector2 w = P - A;
		float theta = v.AngleBetween(w);

		float comp = w.Component(v);

		if(comp > 1)
		{
			closestPt.x = B.x;
			closestPt.y = B.y;
		}
		else if(comp < -1)
		{
			closestPt.x = A.x;
			closestPt.y = A.y;
		}
		else
		{
			closestPt.x = (B.x - A.x) * comp;
			closestPt.y = (B.y - A.y) * comp;
		}
		

		return (w.Norm() * sin(theta));
   }

   /**
    * Determines if the current segment intersects the specified segment.
    * If an intersect occurs the intersectPt is determined.  Note: the
    * case where the lines overlap is not considered.
    * @param   segment        Segment to determine intersection with.
    * @param   intersectPt    (OUT) Intersection point.
    * @return   Returns true if an intersection exists, false if not.
    */
   bool Intersect(const LineSegment2& segment, Point2& intersectPt)
   {
		//Student to define (DrawLines HW)
		Vector2 BA = B - A;
		Vector2 DC = segment.B - segment.A;
		Vector2 CA = segment.A - A;

		float t = CA.Cross(DC) / BA.Cross(DC);
		float u = CA.Cross(BA) / BA.Cross(DC);
		
		if(t >= 0.0 && t <= 1.0
			&& u >= 0.0 && u <= 1.0)
		{
			intersectPt = A + BA*t;
			return true;
		}

		return false;
   }

   /**
    * Clips the line segment to a specified convex polygon.
    * @param  poly  A counter-clockwise oriented polygon.
    * @returns   Returns the clipped segment.
    */
   bool ClipToPolygon(std::vector<Point2>& poly, LineSegment2& clipSegment)
   {
      // Later...
      return true;
   }

   /**
    * Clips the line segment to a specified rectangle.
    * @param  poly  A counter-clockwise oriented polygon.
    * @returns   Returns the clipped segment.
    */
   bool ClipToRectangle(const CRectangle& r, LineSegment2& clip)
   {
      // Later...
      return true;
   }
};

#endif
